package com.hqd.ch03.v33.web.servlet.mvc.condition;

import com.hqd.ch03.utils.ObjectUtils;
import com.hqd.ch03.v33.web.bind.annotation.RequestMethod;
import com.hqd.ch03.v33.web.http.HttpMethod;

import javax.servlet.DispatcherType;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

public class RequestMethodsRequestCondition extends AbstractRequestCondition<RequestMethodsRequestCondition> {

    private static final Map<String, RequestMethodsRequestCondition> requestMethodConditionCache;

    static {
        /**
         * HTTP协议规定的方法，直接初始化
         */
        requestMethodConditionCache = new HashMap<>(RequestMethod.values().length);
        for (RequestMethod method : RequestMethod.values()) {
            requestMethodConditionCache.put(method.name(), new RequestMethodsRequestCondition(method));
        }
    }


    /**
     * 方法定义的请求方法，由用户自己添加
     */
    private final Set<RequestMethod> methods;


    public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
        this.methods = (ObjectUtils.isEmpty(requestMethods) ?
                Collections.emptySet() : new LinkedHashSet<>(Arrays.asList(requestMethods)));
    }


    private RequestMethodsRequestCondition(Set<RequestMethod> methods) {
        this.methods = methods;
    }


    public Set<RequestMethod> getMethods() {
        return this.methods;
    }

    @Override
    protected Collection<RequestMethod> getContent() {
        return this.methods;
    }


    @Override
    public RequestMethodsRequestCondition combine(RequestMethodsRequestCondition other) {
        if (isEmpty() && other.isEmpty()) {
            return this;
        } else if (other.isEmpty()) {
            return this;
        } else if (isEmpty()) {
            return other;
        }
        Set<RequestMethod> set = new LinkedHashSet<>(this.methods);
        set.addAll(other.methods);
        return new RequestMethodsRequestCondition(set);
    }

    @Override
    public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) {
        if (getMethods().isEmpty()) {
            if (RequestMethod.OPTIONS.name().equals(request.getMethod()) &&
                    !DispatcherType.ERROR.equals(request.getDispatcherType())) {

                return null;
            }
            return this;
        }

        return matchRequestMethod(request.getMethod());
    }


    private RequestMethodsRequestCondition matchRequestMethod(String httpMethodValue) {
        RequestMethod requestMethod;
        try {
            /**
             * 只支持默认方法
             */
            requestMethod = RequestMethod.valueOf(httpMethodValue);
            if (getMethods().contains(requestMethod)) {
                return requestMethodConditionCache.get(httpMethodValue);
            }
            if (requestMethod.equals(RequestMethod.HEAD) && getMethods().contains(RequestMethod.GET)) {
                return requestMethodConditionCache.get(HttpMethod.GET.name());
            }
        } catch (IllegalArgumentException ex) {
        }
        return null;
    }

    @Override
    public int compareTo(RequestMethodsRequestCondition other, HttpServletRequest request) {
        if (other.methods.size() != this.methods.size()) {
            return other.methods.size() - this.methods.size();
        } else if (this.methods.size() == 1) {
            if (this.methods.contains(RequestMethod.HEAD) && other.methods.contains(RequestMethod.GET)) {
                return -1;
            } else if (this.methods.contains(RequestMethod.GET) && other.methods.contains(RequestMethod.HEAD)) {
                return 1;
            }
        }
        return 0;
    }

}
